package com.hui.admin.aop;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hui.admin.annotation.Log;
import com.hui.admin.common.UserContext;
import com.hui.admin.entity.UserDO;
import com.hui.admin.service.LogService;
import com.hui.admin.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Aspect
@Component
public class LogAspect {

    // 记录请求开始时间
    private final ThreadLocal<Long> startTime = new ThreadLocal<>();
    private final LogService logService;
    private final UserService userService;

    public LogAspect(LogService logService, UserService userService) {
        this.logService = logService;
        this.userService = userService;
    }

    @Pointcut("@annotation(com.hui.admin.annotation.Log)")
    public void logPointCut() {
    }

    // 前置操作
    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        startTime.set(System.currentTimeMillis());
    }

    // 后置返回通知
    @AfterReturning(pointcut = "logPointCut()", returning = "ret")
    public void doAfterReturning(JoinPoint joinPoint, Object ret) {
        saveLog(joinPoint, ret, null);
    }

    // 异常通知
    @AfterThrowing(pointcut = "logPointCut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        saveLog(joinPoint, null, e);
    }

    private void saveLog(JoinPoint joinPoint, Object ret, Throwable e) {
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            Log annotation = method.getAnnotation(Log.class);

            // 获取当前请求对象
            ServletRequestAttributes attributes =
                    (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            assert attributes != null;
            HttpServletRequest request = attributes.getRequest();

            // 构造日志对象
            com.hui.admin.entity.LogDO sysLog = new com.hui.admin.entity.LogDO();
            assert annotation != null;
            sysLog.setOperation(annotation.value());
            sysLog.setMethod(joinPoint.getTarget().getClass().getName() + "." + method.getName());
            sysLog.setRequestUrl(request.getRequestURI());
            sysLog.setParams(JSONUtil.toJsonStr(joinPoint.getArgs()));
            sysLog.setCreateTime(LocalDateTime.now());
            sysLog.setTime(System.currentTimeMillis() - startTime.get());
            sysLog.setStatus(e != null ? 0 : 1);
            sysLog.setUsername(getUsername());
            sysLog.setRequestIp(getClientIP(request));
            sysLog.setRequestMethod(request.getMethod());

            // 插入数据库
            logService.save(sysLog);
        } catch (Exception ex) {
            System.err.println("记录日志失败：" + ex.getMessage());
        } finally {
            startTime.remove();
        }
    }

    private String getUsername() {
        Long userCurrentId = UserContext.getCurrentUserId();
        LambdaQueryWrapper<UserDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserDO::getId, userCurrentId);
        return userService.getOne(queryWrapper).getName();
    }


    private String getClientIP(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");

        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        } else if (ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }

        return ip;
    }
}
